home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
qlib205.zip
/
QLIB.ZIP
/
SRC
/
STARTUP
/
KEYINIT.ASM
< prev
next >
Wrap
Assembly Source File
|
1997-06-11
|
11KB
|
437 lines
;included by c0.asm
; =========================================================================
; Keyboard Driver Version 1.31
; =========================================================================
; The keyboard driver sets up IRQ handlers and allows better access to the
; keyboard which BIOS just can not do.
; You can:
; - getch(), getche(), getchw(), ungetch()
; - block certain keys from being directed RMODE (which will disable
; ctrl+break and ctrl+alt+del
; - setup lights on the kbd
; - block the LOCK keys from going to RMODE
; There is also 3 sets of tables maintained by the handler which you can
; peek into anytime to see which keys are currently held in.
; There are many keys on the keyboard which are a double of another (like
; the enter key on the keypad), all these keys are called grey keys and
; are preceded by an 0e0h code from the kbd. When these keys are held in
; table#2 is used and if it is not a grey key then table#1 is used.
; Table#0 is basically table#1 OR table#2.
; So if you don't care which CTRL the user
; is holding in just look in table#0. These tables are each 128 bytes
; and each byte is either 1 (held in) or 0 (!held in). Each byte corresponds
; to that keys scan code. (ie: key_tab[1] is the ESC key)
; =========================================================================
; NEW : ver 1.31
; - added _getch() which returns (100h + scan code) if it was a 0 + scan code
; key that was pressed.
; NEW : ver 1.3
; - total overhaul, now is idendical to ANSI C (which sucks) but now
; supports multi-language kbds which is very important
; - added ungetch() - NOTE : only one key can be unget at a time
; NEW : ver 1.2
; - all IRQs are sent to RMODE (and therefore all LOCKS are handled by BIOS)
; - some keys may be blocked from going to RMODE to prevent Ctrl+brk and
; ctrl+alt+del (key_block())
; - can also prevent LOCK keys from going to RMODE (key_block_locks())
; - 64 byte buffer added
; - can set lights (also updates BIOS's flags)
; NEW : ver 1.1
; - key_init is now called on startup (within c0.asm)
.data
align 4
key_tab db 128 dup (0) ;Table #0 Current keys held in (1 OR 2)
key_tab1 db 128 dup (0) ;Table #1 (keys held in w/o preceding 0e0h)
key_tab2 db 128 dup (0) ;Table #2 (keys held in w/ preceding 0e0h)
e0h db 0 ;indicates if the last key typed started with an 0e0h
;or an 0e1h (ver 1.2)
;this is true on all keypad keys, the right ALT,CTRL
;and other things... When this is true key_tab2 is used when
;keys are pressed/released (instead of key_tab1)
align 4
old_int df ? ;old PMODE IRQ handler
ack db 0 ;ACK that command was sent
resend db 0 ;resend last command/data
sending_data db 0 ;flag : currently sending data to kbd
block_e0 db 0 ;when set all keys starting with 0e0h are not sent to
;RMODE.
; (plus CTRL just in case - to prevent CTRL+ALT+DEL)
; This includes break,del,ins,home,end,pgu,pgd,arrow keys,
; right ctrl,right alt,enter(on keypad only)
; Great to disable Ctrl+break and Ctrl+alt+del.
; Use key_block(x) to do this. (1=YES 0=NO)
paws db 0 ;Pause key sequence is coming (e1 1d 45 e1 9d c5)
block_locks db 0 ;when set all LOCK keys are not sent to RMODE
ungetch_flg db 0 ;set if a key is waiting for getch using ungetch
ungetch_char db 0 ;char waiting when using ungetch
.code
; waits till kbd is not busy
kb_wait proc private
;don't use edx!!
mov ecx,10000h
@@:
in al,64h
test al,2
jz @f
dec ecx
jnz @b
@@:
ret
kb_wait endp
align 4
;send data to kbd
key_send proc private,data:byte
mov edx,3 ;# of reties
retry:
call kb_wait
mov ack,0
mov resend,0
mov al,data
out 60h,al
mov ecx,20000h
@@:
push edx ;
mov dx,388h ;non-destructive port
in al,dx ;
pop edx ;waste some time
.if ack
xor eax,eax
ret
.endif
.if resend
dec edx
jnz retry
mov eax,1 ;did not send
ret
.endif
dec ecx
jnz @b
mov eax,1 ;did not send
ret
key_send endp
;this empty's the kbd input/output buffers (scraps everything)
empty_8042 proc private
call _delay
in al,64h
test al,1
jz no_output
call _delay
in al,60h
jmp empty_8042
no_output:
test al,2
jnz empty_8042
ret
empty_8042 endp
;sets the lights on the kbd and updates the BIOS flags
key_lights proc,a:byte
mov sending_data,1 ;we are sending data!
callp empty_8042
callp key_send,0edh ;send set lights command
.if eax ;successful?
mov sending_data,0 ;nope!
ret
.endif
callp key_send,a ;send data (bits 0-2 are the lights)
.if eax
mov sending_data,0
ret
.endif
;update BIOS flags
.if a & 1 ;SCROOL LOCK bit
or byte ptr gs:[417h],(1h SHL 4)
.else
and byte ptr gs:[417h],0ffh XOR (1h SHL 4)
.endif
.if a & 4 ;CAPS
or byte ptr gs:[417h],(1 SHL 6)
.else
and byte ptr gs:[417h],0ffh XOR (1h SHL 6)
.endif
.if a & 2 ;NUM LOCK
or byte ptr gs:[417h],(1 SHL 5)
.else
and byte ptr gs:[417h],0ffh XOR (1h SHL 5)
.endif
mov sending_data,0 ;done sending data
xor eax,eax
ret
key_lights endp
_delay proc private
jmp $+2
ret
_delay endp
align 4
;PMODE IRQ handler
key_pmirq:
call key_irqhand
sti
iretd
align 4
;this is the main IRQ handler
key_irqhand proc private
push ds
push es
push gs
pushad
mov ds,cs:seldata
mov es,seldata
mov gs,selzero
call kb_wait
xor eax,eax
in al,60h ;get data from kbd
.if paws ;if the paws sequence is coming then just ignore the data
dec paws
.if block_e0 ;if 0e0h is disabled then just IRET
jmp key_done
.endif
jmp key_iend ;else redirect to RMODE
.endif
.if al==0fah ;ACK (means the kbd successfully recieved the command/data)
.if sending_data ;if we are sending data to the kbd we need the ACK
mov ack,1
jmp key_done
.endif
jmp key_iend ;else send to RMODE
.endif
.if al==0feh ;resend (means kbd did not get command/data)
.if sending_data
mov resend,1
jmp key_done
.endif
jmp key_iend
.endif
.if sending_data ;ignore everything else while sending data
jmp key_done
.endif
.if al==0e0h ;it's the 0e0h prefix (next key is a grey key)
mov e0h,1 ;set flag
.if block_e0 ;block e0h from going to RMODE?
jmp key_done ;yes
.endif
jmp gotoRMODE ;no
.endif
.if al==0e1h ;this is the 1st byte of the PAUSE sequence
mov paws,5 ;ignore next 5 codes
mov e0h,1 ;the PAUSE key is considered to have a 0e0h prefix
jmp key_iend ;so that if you disable 0e0h this will also not goto RMODE
.endif
.if (e0h) ;detect wachy keys
.if al==37h ;Print Screen make (e0 2a e0 37)
mov al,7eh ;this is the new scan code (look in toascii for it's ASCII)
mov e0h,0
.elseif al==0b7h ;print screen break (e0 b7 e0 aa)
mov e0h,0
mov al,7eh+80h
.elseif al==46h ;Ctrl+brk code (e0 46 e0 c6) (ignored)
jmp key_iend ;
.elseif al==0aah ;
jmp key_iend ;
.elseif al==2ah ;
jmp key_iend ;
.elseif al==0c6h ;
jmp key_iend ; other stuff I must ignore
.elseif al==036h ;
jmp key_iend ;
.elseif al==0b6h ;
jmp key_iend
.endif
.else
.if al==54h
mov al,7eh
.elseif al==0d4h
mov al,7eh+80h
.endif
.endif
mov ebx,offset key_tab
add ebx,eax
;when bit 7 of al =1 then al=(scan code of key released + 128)
; =0 then al=(scan code of key pressed)
test al,128
jz @f
;key released
sub ebx,128 ;remove 80h from al
.if e0h ;was last byte 0e0h?
add ebx,256 ;goto tab2
mov byte ptr[ebx],0
sub ebx,128 ;goto tab1
.if !byte ptr[ebx]
sub ebx,128 ;goto tab
mov byte ptr[ebx],0
.endif
.else
add ebx,128 ;goto tab1
mov byte ptr[ebx],0
add ebx,128 ;goto tab2
.if !byte ptr[ebx]
sub ebx,256 ;goto tab
mov byte ptr[ebx],0
.endif
.endif
jmp key_iend
@@:
;key pressed
mov byte ptr[ebx],1
.if e0h
add ebx,256 ;goto tab2
mov byte ptr[ebx],1
.else
add ebx,128 ;goto tab1
mov byte ptr[ebx],1
.endif
key_iend:
.if (block_e0) && (e0h)
mov e0h,0
jmp key_done ;do not redirect to RMODE
.endif
mov e0h,0
.if (block_e0) && (al==1dh) ;stop CTRL from going to RMODE
jmp key_done ;do not redirect to RMODE
.endif
.if block_locks
.if (al==3ah) || (al==45h) || (al==46h) ;disable LOCK keys
jmp key_done ;do not redirect to RMODE
.endif
.endif
gotoRMODE:
;call old int #9
pushfd
call old_int
jmp @f
key_done:
mov al,20h
out 20h,al
@@:
popad
pop gs
pop es
pop ds
ret
key_irqhand endp
key_init proc private
callp getint,9
mov wptr[old_int+4],ax
mov dptr[old_int],edx
mov cx,cs
callp setint,9,cx,offset key_pmirq
ret
key_init endp
align 4
getchar proc uses ebx
jmp _getch_ ;it's the EXACT same
getchar endp
getch proc uses ebx
;waits till a key is pressed
_getch_::
.if ungetch_flg
xor eax,eax
mov al,ungetch_char
mov ungetch_flg,0
ret
.endif
mov ax,700h
int 21h
movzx eax,al
ret
getch endp
_getch proc
call getch
.if !al
call getch
inc ah ;100h
.endif
ret
_getch endp
getchw proc uses ebx ;get key w/o waiting
;does NOT wait till a key is pressed
call kbhit
.if eax
call getch
.endif
ret
getchw endp
dat db ?
getche proc
call getch
push ax
mov dat,al
invoke write,1,offset dat,1
pop ax
ret
getche endp
kbhit proc
.if ungetch_flg
mov eax,1
ret
.endif
mov ah,0bh
int 21h
movzx eax,al
ret
kbhit endp
key_block proc,x:byte ;Block some keys from going to RMODE
mov al,x ;this will prevent PAUSE,Ctrl^brk,Ctrl^alt^del
.if al ;plus much more
mov al,1
.else
mov al,0
.endif
mov block_e0,al
xor eax,eax
ret
key_block endp
;if you want to set the lights are stop the user from changing them then:
; key_block_locks(1)
; key_lights(x) ;set lights
key_block_locks proc,x:byte ;Block NUM/CAPS/SCROLL LOCKS from going to RMODE
mov al,x
.if al
mov al,1
.else
mov al,0
.endif
mov block_locks,al
and byte ptr gs:[418h],0ffh XOR (5 shl 4) ;shut off keys in BIOS
xor eax,eax
ret
key_block_locks endp
ungetch proc,a:byte
.if ungetch_flg
mov eax,ERROR
ret
.endif
mov al,a
mov ungetch_char,al
mov ungetch_flg,1
xor eax,eax
ret
ungetch endp